

package com.coder.rental.security;

import cn.hutool.core.util.StrUtil;
import com.coder.rental.utils.JwtUtils;
import com.coder.rental.utils.RedisUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
@Component
public class VerifyTokenFilter extends OncePerRequestFilter {
    @Value("${request.login-url}")
    private String loginUrl;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private CustomerUserDetailsService customerUserDetailsService;
    @Resource
    private LoginFailHandler loginFailHandler;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String url = request.getRequestURI();

        // 如果是登录请求，直接放行
        if (StrUtil.equals(url, loginUrl)) {
            filterChain.doFilter(request, response);
            return; // 关键：这里需要返回
        }

        // 非登录请求，进行token验证
        try {
            validateToken(request, response);
            filterChain.doFilter(request, response); // 验证通过后继续执行
        } catch (AuthenticationException e) {
            loginFailHandler.onAuthenticationFailure(request, response, e);
            // 关键：这里不需要再调用 filterChain.doFilter，因为认证已经失败
        }
    }
    private void validateToken(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        String token = request.getHeader("token");
        if (StrUtil.isEmpty(token)) {
            token = request.getParameter("token");
        }
        if (StrUtil.isEmpty(token)) {
            throw new CustomerAuthenticationException("token is empty");
        }
        String tokenKey = "token:" + token;
        String tokenValue = redisUtils.get(tokenKey);
        if (StrUtil.isEmpty(tokenValue)) {
            throw new CustomerAuthenticationException("token已过期");
        }
        if (!StrUtil.equals(tokenValue, token)) {
            throw new CustomerAuthenticationException("token错误");
        }
        String username = JwtUtils.parseToken(token).getClaim("username").toString();
        if (StrUtil.isEmpty(username)) {
            throw new CustomerAuthenticationException("token解析失败");
        }
        UserDetails userDetails = customerUserDetailsService.loadUserByUsername(username);
        if (userDetails == null) {
            throw new CustomerAuthenticationException("用户不存在");
        }
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                userDetails, null, userDetails.getAuthorities());
        authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
    }
}